#include "device.h"
#include "component.h"

#define GSENSOR_LOG(format, ...) OSAL_LOG(C_BLUE format C_NONE, ##__VA_ARGS__)
#define __GSENSOR_LOG(format, ...) __OSAL_LOG(C_BLUE format C_NONE, ##__VA_ARGS__)

#define EVENT_TIME_OUT 0X00000001

/* Virtual hardware interface */
#define IIC_VHW_GSENSOR vIIC_0
#define IRQ_VHW_GSENSOR vPIN_I0

/* I2C Device Address 7 bit format */
#define IIC_ADDR_GSENSOR 0X18

/* Device Identification (Who am I) */
#define LIS2DH12_ID 0x33U

/* LIS2DH register */
#define LIS2DH12_WHO_AM_I 0x0FU
#define LIS2DH12_CTRL1 0x20U
#define LIS2DH12_CTRL2 0x21U
#define LIS2DH12_CTRL3 0x22U
#define LIS2DH12_CTRL4 0x23U
#define LIS2DH12_CTRL5 0x24U
#define LIS2DH12_CTRL6 0x25U
#define LIS2DH12_REFERENCE 0x26U
#define LIS2DH12_OUT_X_L 0x28U
#define LIS2DH12_CLICK_CFG 0x38U
#define LIS2DH12_CLICK_SRC 0x39U
#define LIS2DH12_CLICK_THS 0x3AU
#define LIS2DH12_TIME_LIMIT 0x3BU
#define LIS2DH12_TIME_LATENCY 0x3CU
#define LIS2DH12_TIME_WINDOW 0x3DU

/*******************************************************************************
* Register      : CTRL3
* Address       : 0X22
* Bit Group Name: ST
* Permission    : RW
*******************************************************************************/
typedef enum
{
    LIS2DH12_ST_NORMAL = 0X00,
    LIS2DH12_ST_POS_SIGN = 0X02,
    LIS2DH12_ST_NEG_SIGN = 0X40,
    LIS2DH12_ST_NOT_AVAIL = 0X60,
} LIS2DH12_ST_enum_t;

#define LIS2DH12_ST_MASK 0x06
#define GSENSOR_SENSITIVITY_LOW     30
#define GSENSOR_SENSITIVITY_MID     20
#define GSENSOR_SENSITIVITY_HIGH    10

static uint8_t  publish_msg[2] = {0};

static TimerHandle_stu_t timerHandle = NULL;

static FunctionalState gsensor_status = DISABLE;
static uint8_t user_id = 0; //谁使能禁能的
// static uint8_t sensor_type = LIS2DH12_ID;

static void Gsensor_TimeoutDisable(TimerHandle_stu_t t);
static void Gsensor_Disable(void);



static ErrorStatus Gsensor_Read(uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    if (Device_Write(IIC_VHW_GSENSOR, &reg_addr, 1, IIC_ADDR_GSENSOR) == 0)
    {
        return (Device_Read(IIC_VHW_GSENSOR, data, len, IIC_ADDR_GSENSOR) == 0) ? SUCCESS : ERROR;
    }
    return ERROR;
}

static ErrorStatus Gsensor_Write(uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    uint8_t buffer[10] = {0};

    buffer[0] = reg_addr;
    memcpy(&buffer[1], data, len);
    return (Device_Write(IIC_VHW_GSENSOR, buffer, len + 1, IIC_ADDR_GSENSOR) == 0) ? SUCCESS : ERROR;
}

static ErrorStatus Gsensor_Write_Reg(uint8_t reg_addr, uint8_t value)
{
    return Gsensor_Write(reg_addr, &value, 1);
}

static ErrorStatus Gsensor_SoftReset(void)
{
    ErrorStatus ret;
    uint8_t ctrl5 = 0;
    ret = Gsensor_Read(LIS2DH12_CTRL5, (uint8_t *)&ctrl5, 1);

    if (ret == SUCCESS)
    {
        ctrl5 |= 0x80;
        ret = Gsensor_Write(LIS2DH12_CTRL5, (uint8_t *)&ctrl5, 1);
    }
    return ret;
}

static ErrorStatus Gsensor_GetClickSrc(uint8_t *src)
{
    return Gsensor_Read(LIS2DH12_CLICK_SRC, src, 1);
}

static void Gsensor_ConfigClick(void)
{
    uint8_t value =0;
    /* config click mode */
    Gsensor_SoftReset();
    OSAL_DelayUs(100);

    Gsensor_Write_Reg(LIS2DH12_CTRL1, 0x0f);      //set data rate: disable, lp mode, enable X/Y/Z axis
    Gsensor_Write_Reg(LIS2DH12_CTRL4, 0x00);      //scale selection : 2g
    Gsensor_Write_Reg(LIS2DH12_CLICK_CFG, 0x15);  //enable interrupt single-click on X/Y/Z axis
    Gsensor_Write_Reg(LIS2DH12_CTRL6, 0x02);      //set interrupt active low
    Gsensor_Write_Reg(LIS2DH12_CTRL3, 0x80);      //enable click interrupt on INT1 pin
    // Gsensor_Write_Reg(LIS2DH12_CLICK_THS, 0x87);  //Latch interrupt request / threshold : 9 * ?
    OSAL_NvRead(0, &value, sizeof(value));
    if(value == 0 || value ==0xFF)
    {
       value = 20; //默认中
    }
    value |=0x80;
    Gsensor_Write_Reg(LIS2DH12_CLICK_THS, value);  //Latch interrupt request / threshold : 9 * ?
    Gsensor_Write_Reg(LIS2DH12_TIME_LIMIT, 0xff); //255 * 2.5ms

    value = 0X90;
    Gsensor_Write(0x1E, (uint8_t *)&value, 1); //pull-up disconnected to SDO/SA0 pin
}

/**
  * @brief  Gsensor的INT触发后，执行这个函数
  *         
  * @note   判断sensor具体产生了哪个触发
  */
static uint32_t Gsensor_ProcessISR(FlagStatus opt)
{
    uint8_t tap_src = 0;
    GSENSOR_LOG("Gsensor_ProcessISR\r\n");
    if (Gsensor_GetClickSrc(&tap_src) == SUCCESS)
    {
        if (tap_src & 0x40)
        {
            if (tap_src & 0x20)
            {
                GSENSOR_LOG("double tap, %02x\r\n", tap_src & 0x07);
                return 2;
            }
            else if (tap_src & 0x10)
            {
                GSENSOR_LOG("single tap, %02x\r\n", tap_src & 0x07);
                publish_msg[0] =1;
                publish_msg[1] = user_id;
                if (opt == SET)
                {
                    OSAL_MessagePublish(&publish_msg, sizeof(publish_msg));
                    memset(publish_msg, 0, sizeof(publish_msg));
                }
                return 1;
            }
        }
    }
    return 0;
}

/**
  * @brief  INT引脚中断回调
  *         
  * @note   在中断里面执行的，这里一般设置ISR事件即可，不要做过多的逻辑
  */
static void Gsensor_IrqHandle(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
    if (gsensor_status == ENABLE)
    {
        OSAL_EventCreateFromISR(COMP_GSENSOR);
    }
}

/**
  * @brief  唤醒回调
  *         
  * @note   休眠状态下INT触发：会执行这个CB
  * @return 返回0：不唤醒， 返回非0：唤醒
  */
static int32_t Gsensor_WakeHandle(uint32_t dev)
{
    if (gsensor_status == ENABLE)
    {
        return Gsensor_ProcessISR(RESET);
    }
    return 0;
}
COMPONENT_WAKEUP_EXPORT(COMP_GSENSOR, Gsensor_WakeHandle, IRQ_VHW_GSENSOR);

/**
  * @brief  加速度传感器初始化
  *         
  * @note   
  */
static void Gsensor_Init(void)
{
    static FlagStatus power_on = SET;

    if (power_on == SET)
    {
        power_on = RESET;

        /* read device id */
        uint8_t id = 0;
        Gsensor_Read(LIS2DH12_WHO_AM_I, &id, 1);
        if (id != LIS2DH12_ID)
        {
            GSENSOR_LOG("read id err, %02x\r\n", id);
            return;
        }

        /* 配置单击检测 */
        Gsensor_ConfigClick();

        /* 注册中断回调 */
        Device_RegisteredCB(IRQ_VHW_GSENSOR, Gsensor_IrqHandle);
        gsensor_status = DISABLE;
        GSENSOR_LOG("gsensor init success\r\n");
    }
}

static void Gsensor_Disable(void)
{
    uint8_t value = 0x00;
    uint8_t tap_src = 0;
    Gsensor_GetClickSrc(&tap_src);
    Gsensor_Read(LIS2DH12_CTRL1, (uint8_t *)&value, 1);
    value &= 0x0f;
    Gsensor_Write(LIS2DH12_CTRL1, (uint8_t *)&value, 1); //set data rate: disable
}

static void Gsensor_Enable(void)
{
    uint8_t value = 0x00;
    Gsensor_Read(LIS2DH12_CTRL1, (uint8_t *)&value, 1);
    value &= 0x0f;
    value |= 0x60;
    Gsensor_Write(LIS2DH12_CTRL1, (uint8_t *)&value, 1); //set data rate: 200Hz
}

/*
灵敏度设置范围  7bit大小  
约小越不灵敏
*/
static ErrorStatus Gsensor_SetLevel(uint8_t level)
{
    uint8_t value;
    if (level == 1)
    {
        value = GSENSOR_SENSITIVITY_LOW;
    }
    else if (level == 2)
    {
        value = GSENSOR_SENSITIVITY_MID;
    }
    else if (level == 3)
    {
        value = GSENSOR_SENSITIVITY_HIGH; //最高震动灵敏度
    }
    else
    {
        return ERROR;
    }
    GSENSOR_LOG("Gsensor_SetLevel(%d)\r\n", level);
    value |= 0x80;
    Gsensor_Write(LIS2DH12_CLICK_THS, (uint8_t *)&value, 1); //set tap threshold
    OSAL_NvWrite(0, &value, sizeof(value));
    return SUCCESS;
}

/**
  * @brief  设置Gsensor状态
  *    
  * @param  status：使能、禁能
  */
static ErrorStatus Gsensor_SetStatus(FunctionalState status, uint32_t time, uint8_t userId)
{
    if (status == DISABLE)
    {
        Gsensor_Disable();
        if (timerHandle != NULL)
        {
            OSAL_TimerDelete(timerHandle);
            timerHandle = NULL;
        }

        gsensor_status = DISABLE;
        // user_id = userId;
        GSENSOR_LOG("gsensor disable\r\n");
    }
    else if (status == ENABLE)
    {
        Gsensor_Enable();
        gsensor_status = ENABLE;
        user_id = userId;
        GSENSOR_LOG("gsensor enable, time:%ld\r\n", time);

        timerHandle = OSAL_TimerCreate(Gsensor_TimeoutDisable, time * 1000, RESET); //创建定时时间，关闭gsensor
    }
    return SUCCESS;
}

static void Gsensor_TimeoutDisable(TimerHandle_stu_t t)
{
    (void)t;
    OSAL_EventSingleCreate(COMP_GSENSOR, EVENT_TIME_OUT, 0, EVT_PRIORITY_MEDIUM);
    timerHandle = NULL;
}

static ErrorStatus Gsensor_Write_ST(LIS2DH12_ST_enum_t newValue)
{
    uint8_t value;

    if (!Gsensor_Read(LIS2DH12_CTRL4, &value, 1))
        return ERROR;

    value &= ~LIS2DH12_ST_MASK;
    value |= newValue;

    if (!Gsensor_Write(LIS2DH12_CTRL4, &value, 1))
        return ERROR;

    return SUCCESS;
}

/**
  * @brief  Gsensor自检是否功能正常
  *    
  * @param  status：使能、禁能
  */
static ErrorStatus Gsensor_self_test(void)
{
    static FlagStatus power_on = SET;
    // ErrorStatus ret;
    int16_t dataN[3] = {0}; //正常模式下的数据
    int16_t dataT[3] = {0}; //self-test模式下的数据
    // int32_t dataTemp;
    if (power_on == SET)
    {
        power_on = RESET;
        /* read device id */
        uint8_t id = 0;
        Gsensor_Read(LIS2DH12_WHO_AM_I, &id, 1);
        if (id != LIS2DH12_ID)
        {
            return ERROR;
        }
        Gsensor_SoftReset();
        OSAL_DelayUs(100);
        GSENSOR_LOG("gsensor init success\r\n");
    }

    Gsensor_Write_Reg(LIS2DH12_CTRL1, 0x77); //400hz
    Gsensor_Write_Reg(LIS2DH12_CTRL4, 0x00); //scale selection : 2g

    /* 设置为正常模式 */
    Gsensor_Write_ST(LIS2DH12_ST_NORMAL);
    Device_DelayMs(5);

    uint8_t data[6];
    int i = 0;
    for (i = 0; i < 6; i++)
    {
        Gsensor_Read(LIS2DH12_OUT_X_L + i, &data[i], 1);
    }
    for (i = 0; i < 6; i += 2)
    {
        dataN[i / 2] = (int16_t)((data[i + 1] << 8) | data[i]) >> 4;
    }

    GSENSOR_LOG("dataN[0] = %d, dataN[1] = %d, dataN[2] = %d\r\n", dataN[0], dataN[1], dataN[2]);

    /* 设置为self-test模式 */
    Gsensor_Write_ST(LIS2DH12_ST_POS_SIGN);
    Device_DelayMs(5);
    for (i = 0; i < 6; i++)
    {
        Gsensor_Read(LIS2DH12_OUT_X_L + i, &data[i], 1);
    }
    for (i = 0; i < 6; i += 2)
    {
        dataT[i / 2] = (int16_t)((data[i + 1] << 8) | data[i]) >> 4;
    }

    GSENSOR_LOG("dataT[0] = %d, dataT[1] = %d, dataT[2] = %d\r\n", dataT[0], dataT[1], dataT[2]);

    int16_t delta_x = abs(dataT[0] - dataN[0]);
    int16_t delta_y = abs(dataT[1] - dataN[1]);
    int16_t delta_z = abs(dataT[2] - dataN[2]);

    GSENSOR_LOG("delta_x = %d,  delta_y = %d, delta_z = %d \r\n", delta_x, delta_y, delta_z);
    if (delta_x < 70 || delta_x > 1500 || delta_y < 70 || delta_y > 1500 || delta_z < 70 || delta_z > 1500)
    {
        GSENSOR_LOG("gsensor self test error\r\n");
        return ERROR;
    }
    else
    {
        GSENSOR_LOG("gsensor self test succeed\r\n");
    }
    Gsensor_ConfigClick();
    return SUCCESS;
}


static uint8_t Gsensor_get_level(void)
{
    uint8_t level =2;
    OSAL_NvRead(0, &level, sizeof(level));
    level = level & 0x7f;
    GSENSOR_LOG("Gsensor_get_level :%d\r\n",level);
    if(level == GSENSOR_SENSITIVITY_LOW)
    {
        level = 1;
    }
    else if(level == GSENSOR_SENSITIVITY_MID)
    {
        level = 2;
    }
    else if(level == GSENSOR_SENSITIVITY_HIGH)
    {
        level = 3;
    }
    else
    {
        level = 2;
    }
    return level;
}
/**
  * @brief  加速度传感器任务函数
  *
  * @note
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Gsensor_Task(uint32_t event)
{
    /* 系统启动事件 */
    if (event & EVENT_SYS_START)
    {
        GSENSOR_LOG("Gsensor task start\r\n");

        Gsensor_Init();
        Device_ConfigCB(IRQ_VHW_GSENSOR, ENABLE);

        if (publish_msg[0] != 0)
        {
            OSAL_MessagePublish(&publish_msg, sizeof(publish_msg));
            memset(publish_msg, 0, sizeof(publish_msg));
        }

        SYS_API(Gsensor_SetStatus);
        SYS_API(Gsensor_SetLevel);
        SYS_API(Gsensor_self_test);
        SYS_API(Gsensor_get_level);
        return (event ^ EVENT_SYS_START);
    }

    /* 系统休眠事件 */
    if (event & EVENT_SYS_SLEEP)
    {
        Device_ConfigCB(IRQ_VHW_GSENSOR, DISABLE);
        return (event ^ EVENT_SYS_SLEEP);
    }

    /* 系统中断事件 */
    if (event & EVENT_SYS_ISR)
    {
        Gsensor_ProcessISR(SET);
        return (event ^ EVENT_SYS_ISR);
    }

    if (event & EVENT_TIME_OUT)
    {
        uint8_t  msg[2] = {0};
        msg[0] =2;//超时
        GSENSOR_LOG("gsensor timeout\r\n");
        OSAL_MessagePublish(&msg, sizeof(msg));
        Gsensor_SetStatus(DISABLE, 0, 0);
        return (event ^ EVENT_TIME_OUT);
    }
    return 0;
}
COMPONENT_TASK_EXPORT(COMP_GSENSOR, Gsensor_Task, 2);
